
#include "av_recorder.h"
#include "log_print.h"

AvRecorder &AvRecorder::GetInstance()
{
    static AvRecorder instance;
    return instance;
}

void AvRecorder::OnCameraInputError(const Camera_Input* cameraInput, Camera_ErrorCode errorCode)
{
    LOGI("on camera input error code:%{public}d", errorCode);
}

CameraInput_Callbacks* AvRecorder::GetCameraInputListener(void)
{
    static CameraInput_Callbacks inputCall = {
        .onError = OnCameraInputError
    };
    return &inputCall;
}

void AvRecorder::OnFocusStateChange(Camera_CaptureSession* session, Camera_FocusState focusState)
{
    LOGI("capture session onfocus state change");
}

void AvRecorder::CaptureSessionOnError(Camera_CaptureSession* session, Camera_ErrorCode errorCode)
{
    LOGI("capture session error code: %{public}d", errorCode);
}

CaptureSession_Callbacks* AvRecorder::GetCaptureSessionRegister()
{
    static CaptureSession_Callbacks captureCall = {
        .onFocusStateChange = OnFocusStateChange,
        .onError = CaptureSessionOnError
    };
    return &captureCall;
}

void AvRecorder::VideoOutputOnFrameStart(Camera_VideoOutput* videoOutput)
{
    LOGI("video output on frame start");
}

void AvRecorder::VideoOutputOnFrameEnd(Camera_VideoOutput* videoOutput, int32_t frameCount)
{
    LOGI("video output frame count:%{public}d", frameCount);
}

void AvRecorder::VideoOutputOnError(Camera_VideoOutput* videoOutput, Camera_ErrorCode errorCode)
{
    LOGI("video output error code:%{public}d", errorCode);
}

VideoOutput_Callbacks* AvRecorder::GetVideoOutputListener()
{
    static VideoOutput_Callbacks videoOutputListener = {
        .onFrameStart = VideoOutputOnFrameStart,
        .onFrameEnd = VideoOutputOnFrameEnd,
        .onError = VideoOutputOnError
    };
    return &videoOutputListener;
}

void AvRecorder::StatusCallback(Camera_Manager* cameraManager, Camera_StatusInfo* status)
{
    LOGI("camera manager status callback is called");
}

CameraManager_Callbacks* AvRecorder::GetCameraManagerListener()
{
    static CameraManager_Callbacks cameraManagerListener = {
        .onCameraStatus = StatusCallback
    };
    return &cameraManagerListener;
}

Camera_ErrorCode AvRecorder::GetSupportCameras()
{
    auto ret = OH_Camera_GetCameraManager(&cameraManager_);
    if (cameraManager_ == nullptr || ret != CAMERA_OK) {
        LOGE("get camera mananger failed.");
        return ret;
    }

    ret = OH_CameraManager_RegisterCallback(cameraManager_, GetCameraManagerListener());
    if (ret != CAMERA_OK) {
        LOGE("camera manager register callback failed");
        return ret;
    }

    ret = OH_CameraManager_GetSupportedCameras(cameraManager_, &cameras_, &size_);
    if (cameras_ == nullptr || size_ < 0 || ret != CAMERA_OK) {
        LOGE("get supported cameras failed.");
        return ret;
    }

    for (int index = 0; index < size_; index++) {
        LOGI("cameraId: %{public}s ", cameras_[index].cameraId);
        LOGI("cameraPosition: %{public}d ", cameras_[index].cameraPosition);
        LOGI("cameraType: %{public}d ", cameras_[index].cameraType);
        LOGI("connectionType: %{public}d ", cameras_[index].connectionType);
    }
    return CAMERA_OK;
}

Camera_ErrorCode AvRecorder::GetCamerasOutputCapability()
{
    auto ret = OH_CameraManager_GetSupportedCameraOutputCapability(cameraManager_,
        &cameras_[cameraDeviceIndex_], &cameraOutputCapability_);
    if (cameraOutputCapability_ == nullptr || ret != CAMERA_OK) {
        LOGE("get supported camera output capability failed.");
        return ret;
    }
    if (cameraOutputCapability_->previewProfilesSize < 0) {
        LOGI("preview profiles size is null");
        return CAMERA_INVALID_ARGUMENT;
    }

    previewProfile_ = cameraOutputCapability_->previewProfiles[0];
    if (cameraOutputCapability_->photoProfilesSize < 0) {
        LOGI("photo profiles size is null");
        return CAMERA_INVALID_ARGUMENT;
    }

    photoProfile_ = cameraOutputCapability_->photoProfiles[0];

    if (cameraOutputCapability_->videoProfilesSize < 0) {
        LOGI("video profiles size is null");
        return CAMERA_INVALID_ARGUMENT;
    }
    videoProfile_ = cameraOutputCapability_->videoProfiles[0];
    return CAMERA_OK;
}

void AvRecorder::ConfigCapSession()
{
    auto ret = OH_VideoOutput_RegisterCallback(videoOutput_, GetVideoOutputListener());
    if (ret != CAMERA_OK) {
        LOGE("video output register callback failed.");
        return;
    }
    ret = OH_CameraManager_CreateCaptureSession(cameraManager_, &captureSession_);
    if (captureSession_ == nullptr || ret != CAMERA_OK) {
        LOGE("camera manager create capture session failed.");
        return;
    }
    ret = OH_CaptureSession_RegisterCallback(captureSession_, GetCaptureSessionRegister());
    if (ret != CAMERA_OK) {
        LOGE("capture session register callback failed.");
        return;
    }
    ret = OH_CaptureSession_BeginConfig(captureSession_);
    if (ret != CAMERA_OK) {
        LOGE("capture session config failed.");
    }
}

void AvRecorder::ConfigInput()
{
    auto ret = OH_CameraManager_CreateCameraInput(cameraManager_, &cameras_[cameraDeviceIndex_], &cameraInput_);
    if (cameraInput_ == nullptr || ret != CAMERA_OK) {
        LOGE("create camera input failed:%{public}d.", static_cast<int>(ret));
        return;
    }
    ret = OH_CameraInput_RegisterCallback(cameraInput_, GetCameraInputListener());
    if (ret != CAMERA_OK) {
        LOGE("camera input register callback failed.");
        return;
    }
    ret = OH_CameraInput_Open(cameraInput_);
    if (ret != CAMERA_OK) {
        LOGE("camera input open failed.");
        return;
    }

    ret = OH_CaptureSession_AddInput(captureSession_, cameraInput_);
    if (ret != CAMERA_OK) {
        LOGE("capture session add input failed:%{public}d.", static_cast<int>(ret));
    }
}

void AvRecorder::PrepareRecorder(const std::string &previewId, const std::string &videoId)
{
    std::string videoSurfaceId = std::move(videoId);
    std::string previewSurfaceId = std::move(previewId);
    auto ret = GetSupportCameras();
    if (ret != CAMERA_OK) {
        LOGE("get supported cameras failed.");
        return;
    }
    ret = GetCamerasOutputCapability();
    if (ret != CAMERA_OK) {
        LOGE("get supported cameras output capability failed.");
        return;
    }
    ret = OH_CameraManager_CreateVideoOutput(cameraManager_, videoProfile_, videoSurfaceId.c_str(), &videoOutput_);
    if (videoProfile_ == nullptr || videoOutput_ == nullptr || ret != CAMERA_OK) {
        LOGE("create video output failed.");
        return;
    }
    ConfigCapSession();
    ConfigInput();
    ret = OH_CameraManager_CreatePreviewOutput(
        cameraManager_, previewProfile_, previewSurfaceId.c_str(), &previewOutput_);
    if (previewProfile_ == nullptr || previewOutput_ == nullptr || ret != CAMERA_OK) {
        LOGE("create preview output failed:%{public}d.", static_cast<int>(ret));
        return;
    }
    ret = OH_CaptureSession_AddPreviewOutput(captureSession_, previewOutput_);
    if (ret != CAMERA_OK) {
        LOGE("add preview output failed.");
        return;
    }
    ret = OH_CaptureSession_AddVideoOutput(captureSession_, videoOutput_);
    if (ret != CAMERA_OK) {
        LOGE("capture session add video output failed.");
        return;
    }
    ret = OH_CaptureSession_CommitConfig(captureSession_);
    if (ret != CAMERA_OK) {
        LOGE("OH_CaptureSession_CommitConfig failed.");
        return;
    }
    ret = OH_CaptureSession_Start(captureSession_);
    if (ret != CAMERA_OK) {
        LOGE("capture session start failed.");
    }
}

void AvRecorder::StartRecorder()
{
    if (videoOutput_ == nullptr) {
        LOGE("video output nullptr.");
        return;
    }
    auto ret = OH_VideoOutput_Start(videoOutput_);
    if (ret != CAMERA_OK) {
        LOGE("video output start failed.");
    }
}

void AvRecorder::StopRecorder()
{
    auto ret = OH_VideoOutput_Stop(videoOutput_);
    if (ret != CAMERA_OK) {
        LOGE("video output stop failed.");
    }
}

void AvRecorder::ReleaseRecorder()
{
    auto ret = OH_CaptureSession_Stop(captureSession_);
    if (ret != CAMERA_OK) {
        LOGE("capture session stop failed:%{public}d ", ret);
        return;
    }
    ret = OH_CameraInput_Close(cameraInput_);
    if (ret != CAMERA_OK) {
        LOGE("camera input close failed:%{public}d ", ret);
        return;
    }
    ret = OH_PreviewOutput_Release(previewOutput_);
    if (ret != CAMERA_OK) {
        LOGE("preview output release failed:%{public}d ", ret);
        return;
    }
    ret = OH_VideoOutput_Release(videoOutput_);
    if (ret != CAMERA_OK) {
        LOGE("video output release failed:%{public}d ", ret);
        return;
    }
    ret = OH_CaptureSession_Release(captureSession_);
    if (ret != CAMERA_OK) {
        LOGE("capture session release failed:%{public}d ", ret);
        return;
    }
    
    ret = OH_CameraManager_DeleteSupportedCameras(cameraManager_, cameras_, size_);
    if (ret != CAMERA_OK) {
        LOGE("delete supported cameras failed.");
        return;
    }
    ret = OH_CameraManager_DeleteSupportedCameraOutputCapability(cameraManager_, cameraOutputCapability_);
    if (ret != CAMERA_OK) {
        LOGE("delete supported camera output capability failed.");
        return;
    }
    ret = OH_Camera_DeleteCameraManager(cameraManager_);
    if (ret != CAMERA_OK) {
        LOGE("delete camera manager failed.");
    }
}